using System;
using System.Collections.Generic;
using System.Data;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sensor.SerialPorts.Enums;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace Sensor.SerialPorts;

public class SerialPortHandler : IDisposable
{
    private readonly SerialPort _serialPort = new();
    private bool disposedValue;


    public Action<Exception>? OnException { get; set; }

    public Action<byte[]>? OnData { get; set; }

    private readonly object _lockObj = new();
    public bool Open(string port, int baudRate, ParityBit parityBit, StopBit stopBit, int dataBit)
    {
        if (_serialPort.IsOpen)
        {
            return Close();
        }

        try
        {
            _serialPort.PortName = port;
            _serialPort.BaudRate = baudRate;
            _serialPort.Parity = SerialPortHelp.GetParity(parityBit.ToString());
            _serialPort.StopBits = SerialPortHelp.GetStopBits(stopBit.ToString());
            _serialPort.DataBits = dataBit;

            // 优化设置以处理高速数据传输
            _serialPort.ReadTimeout = 500;
            _serialPort.WriteTimeout = 500;

            // 设置更大的读写缓冲区大小，对于高速数据传输非常重要
            // 默认值可能不足以处理大量快速到达的数据，导致数据丢失
            _serialPort.ReadBufferSize = 2 * 1024 * 1024;  // 2MB读取缓冲区
            _serialPort.WriteBufferSize = 2 * 1024 * 1024; // 2MB写入缓冲区
            
            // 调整接收数据阈值触发，减少CPU使用率和事件触发频率
            // 对于1Hz频率的数据传输，使用较大的阈值可以减少事件触发次数
            _serialPort.ReceivedBytesThreshold = 64;  // 接收64字节才触发事件，减少事件触发频率

            _serialPort.Open();
            if (_serialPort.IsOpen)
            {
                //清理数据
                _serialPort.DiscardInBuffer();
                _serialPort.DiscardOutBuffer();
                _serialPort.DataReceived += OnDataReceived;
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (Exception ex)
        {
            OnException?.Invoke(ex);
        }
        return false;
    }

    public bool Close()
    {
        try
        {
            if (_serialPort.IsOpen)
            {
                _serialPort.Close();
            }
            return _serialPort.IsOpen;
        }
        catch (Exception ex)
        {
            OnException?.Invoke(ex);
            return false;
        }
    }

    public void Send(byte[] data)
    {
        try
        {
            if (_serialPort.IsOpen)
            {
                lock (_lockObj)
                {
                    _serialPort.Write(data, 0, data.Length);
                }
            }
        }
        catch (Exception ex)
        {
            OnException?.Invoke(ex);
        }
    }

    private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        try
        {
            lock (_lockObj)
            {
                int bytesToRead = _serialPort.BytesToRead;
                if (bytesToRead <= 0) return;

                byte[] buffer = new byte[bytesToRead];
                int bytesRead = _serialPort.Read(buffer, 0, bytesToRead);

                if (bytesRead > 0)
                {
                    OnData?.Invoke(buffer);
                }
            }
        }
        catch (Exception ex)
        {
            OnException?.Invoke(ex);
        }
    }


    #region Dispose
    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                // TODO: 释放托管状态(托管对象)
                _serialPort.DataReceived -= OnDataReceived;
                _serialPort.Dispose();
            }

            // TODO: 释放未托管的资源(未托管的对象)并重写终结器
            // TODO: 将大型字段设置为 null
            disposedValue = true;
        }
    }

    // // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
    // ~SerialPortHandler()
    // {
    //     // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
    //     Dispose(disposing: false);
    // }

    public void Dispose()
    {
        // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
    #endregion

}
OO:托管状态托管对象Disp//TOO: 释放未托管的资源未托管的对象并重写终结器//TODO:将大型字段设置为null